package it.polito.let.jhp;

import it.polito.let.filesystem.FileConstants;
import it.polito.let.filesystem.FileGenericError;
import it.polito.let.filesystem.FileUtil;
import it.polito.let.java.DuplicateAttributeException;
import it.polito.let.java.DuplicateMethodException;
import it.polito.let.java.JavaMethod;
import it.polito.let.java.JavaProgram;
import it.polito.let.jhp.parser.JHPCup;
import it.polito.let.jhp.parser.JHPLex;
import it.polito.let.jhp.types.Value;
import it.polito.let.pages.PagesConstants;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Serializable;
import java.util.List;
import java.util.Map;

public class JHPCompiler {

	private static final String[] PUBLIC = new String[] { "public" };

	public static File compile(File in) throws FileGenericError {
		List<File> fl = null;
		JHPCup parser = null;
		try {
			parser = new JHPCup(new JHPLex(new FileReader(in)));
		} catch (IOException e) {
			throw new FileGenericError("Unable to compile JHP source file: " + in.getName() + " \r\nReason: " + e.getMessage());
		}
		try {
			parser.parse();
		} catch (Exception e) {
			throw new FileGenericError("Unable to compile JHP source file: " + in.getName() + " \r\nReason: " + e.getMessage());
		}

		if (parser.semantic_error != 0 || parser.syntax_error != 0) {
			throw new FileGenericError("Unable to compile JHP source file: " + in.getName() + " \r\nReason: " + parser.getErrorReport());
		}
		String ClassName = FileUtil.randomFileName(PagesConstants.DYNAMIC_BUILD_DIR, FileConstants.JAVABIN, false);
		ClassName = ClassName.substring(0,1).toUpperCase()+ClassName.substring(1).toLowerCase(); // Rename according to Java class naming convention

		JavaProgram myprog = new JavaProgram(ClassName);
		myprog.addImport("java.io.*");
		myprog.addImport("java.util.*");
		myprog.addImport("it.polito.let.http.*");
		myprog.addImport("it.polito.let.util.*");
		myprog.addImport("it.polito.let.jhp.*");
		myprog.addImport("it.polito.let.jhp.types.*");
		myprog.addImport("it.polito.let.jhp.form.*");
		myprog.addImport("it.polito.let.pages.*");
		myprog.addSuffix("extends JHPResponder");
		myprog.addSuffix("implements Page");
		try {
			myprog.addSerAttribute("document", (Serializable) parser.getDocument());
			JavaMethod jm = myprog.addMethod(PUBLIC, "void", "handleRequest", null);
			jm.addThrow("HTTPError");
			jm.appendStatement("super.returnJHPDocument();");

			jm = myprog.addConstructor(PUBLIC, null);
			jm.addThrow("HTTPError");
			jm.appendStatement("super();");
			
			String formCallbacks = parser.getFormCallbacks();
			jm = myprog.addMethod(PUBLIC, "String", "formCallbacks", new String[]{"int id","Map<String, Value> POST"});
			jm.appendStatement("ByteArrayOutputStream _out = new ByteArrayOutputStream();");
			jm.appendStatement("PrintStream out = new PrintStream(_out);");
			jm.appendStatement("switch (id) {");
			jm.appendStatement(formCallbacks);
			jm.appendStatement("default:");
			jm.appendStatement("break;");
			jm.appendStatement("}");
			jm.appendStatement("return _out.toString();");



			myprog.appendStatement(parser.getGlobalStatement());

			fl = myprog.generateJavaCode(PagesConstants.GENERATED_SRC_DIR);
		} catch (IOException e) {
			throw new FileGenericError("Unable to generate compiled JHP file: " + in.getName() + " \r\nReason: " + e.getMessage());
		} catch (DuplicateAttributeException e) {
		} catch (DuplicateMethodException e) {
		}
		return fl.get(0);
	}
}
